package triangleindex;
import java.awt.geom.Point2D;
import java.util.ArrayList;

public class Icosahedron {

	public ArrayList<Triangle> ball = new ArrayList<Triangle>();

	float radius = 50;
	float xchange = (float) (50 * Math.sin(Math.PI / 3.0));
	float ori_x = 500;
	float ori_y = 200;

	float max_x = 1000;
	float max_y = 800;

	TriangleIndex index = new TriangleIndex();
	
	
	public float pan_x = 0;
	public float pan_y = 0;

	public Icosahedron() {
		init();
	}

	public void setRadius(float r)
	{
	    	this.radius = r;
	    	
	    	if(this.ball.size()!=0)
	    	{
	    		for(int i = 0 ; i < 20; i ++)
	    		{
	    			ball.get(i).setRadius(this.radius);
	    		}
	    	}
	}
	
	public float getRadius()
	{
		return this.radius;
	}
	
	public float getMax_x() {
		return this.max_x;
	}

	public float getMax_y() {
		return this.max_y;
	}

	public void setMax_x(float x) {
		this.max_x = x;
	}

	public void setMax_y(float y) {
		this.max_y = y;
	}

	public float getOri_x() {

		return this.ori_x;
	}

	public float getOri_y() {
		return this.ori_y;
	}

	public void setOri_x(float x) {
		this.ori_x = x;
	}

	public void setOri_y(float y) {
		this.ori_y = y;
	}

	
	// get the triangle by index
	
	public Triangle getTriangleByIndex(int index){
		Triangle t = null;
		for(int i = 0 ; i < ball.size(); i ++ ){
			if(ball.get(i).getTriIndex() == index)
			{
				t = ball.get(i);
				break;
			}
		}
		return t;
	}
	
	
	public void reLocation(int tempx, int tempy) {
		
		pan_x = tempx;
		pan_y = tempy;
		
		for(int i = 0 ; i < ball.size(); i ++)
		{
			ball.get(i).setLocation(ball.get(i).getX() + pan_x, ball.get(i).getY()+ pan_y);
		}

	//	AdjustIcosa();
	}

	public void AdjustIcosa() {
		// TODO Auto-generated method stub

		for (int i = 0; i < this.ball.size(); i++) {
			
			Point2D location = this.ball.get(i).getLocation();

			// here you should change the format of the function to
			// left,right,up,down
			
			
			if (((location.getX() < 200) || (location.getX() > this.max_x - 200))
					|| ((location.getY() < 100) || (location.getY() > this.max_y -100))) {
				// find out the adjacent triangle
				ArrayList<Triangle> adjTri = new ArrayList<Triangle>();
				
				int[] adjIndex = this.findAdjacentTri(this.ball.get(i)
						.getTriIndex());

			    for(int j = 0 ; j < 20; j ++)
			    {
			    	if((this.ball.get(j).getTriIndex() == adjIndex[0])||(this.ball.get(j).getTriIndex() == adjIndex[1])||this.ball.get(j).getTriIndex() == adjIndex[2])
			   
			        adjTri.add(this.ball.get(j));
			    }
				
				this.ball.get(i).translateToScreen(adjTri);
				
			}
			
		}
		
	}

	public void init() {
		
		/**
		 * switch (h_tri) {
		case 1:
			v1 = 1;
			v2 = 3;
			v3 = 2;
			break;
		case 2:
			v1 = 1;
			v2 = 4;
			v3 = 3;
			break;
		case 4:
			v1 = 1;
			v2 = 5;
			v3 = 4;
			break;
		case 3:
			v1 = 1;
			v2 = 6;
			v3 = 5;
			break;
		case 5:
			v1 = 1;
			v2 = 2;
			v3 = 6;
			break;
		case 6:
			v1 = 2;
			v2 = 3;
			v3 = 8;
			break;
		case 7:
			v1 = 3;
			v2 = 9;
			v3 = 8;
			break;
		case 8:
			v1 = 3;
			v2 = 4;
			v3 = 9;
			break;
		case 9:
			v1 = 4;
			v2 = 10;
			v3 = 9;
			break;
		case 10:
			v1 = 4;
			v2 = 5;
			v3 = 10;
			break;
		case 11:
			v1 = 5;
			v2 = 11;
			v3 = 10;
			break;
		case 12:
			v1 = 5;
			v2 = 6;
			v3 = 11;
			break;
		case 13:
			v1 = 6;
			v2 = 7;
			v3 = 11;
			break;
		case 14:
			v1 = 2;
			v2 = 7;
			v3 = 6;
			break;
		case 15:
			v1 = 2;
			v2 = 8;
			v3 = 7;
			break;
		case 16:
			v1 = 8;
			v2 = 9;
			v3 = 12;
			break;
		case 17:
			v1 = 9;
			v2 = 10;
			v3 = 12;
			break;
		case 18:
			v1 = 10;
			v2 = 11;
			v3 = 12;
			break;
		case 19:
			v1 = 11;
			v2 = 7;
			v3 = 12;
			break;
		case 20:
			v1 = 8;
			v2 = 12;
			v3 = 7;
			break;
		 */
		// TODO Auto-generated method stub
		// initialize the triangles
	

		Triangle tri1 = new Triangle();
		tri1.setLocation(ori_x, ori_y);
		tri1.setOrientation(1);
		int[] nodeIndex1 = { 2, 7, 8 };		
		tri1.setNodeIndex(nodeIndex1);
		
		//for record the changes
		tri1.setNewOrientation(1);
		int[] orIndex1 = { 2, 7, 8 };
		tri1.setOriNodeIndex(orIndex1);
		tri1.setTriIndex(9);
		ball.add(tri1);

		Triangle tri2 = new Triangle();
		tri2.setLocation(ori_x + xchange, (float) (ori_y + radius / 2.0));
		tri2.setOrientation(2);
		int[] nodeIndex2 = { 3, 2, 8 };
		tri2.setNodeIndex(nodeIndex2);
		
		tri2.setNewOrientation(2);
		int[] orIndex2 = { 3, 2, 8 };
		tri2.setOriNodeIndex(orIndex2);
		tri2.setTriIndex(8);
		ball.add(tri2);

		Triangle tri3 = new Triangle();
		tri3.setLocation(ori_x + xchange * 2, ori_y);
		tri3.setOrientation(2);
		int[] nodeIndex3 = { 3, 8, 9 };
		tri3.setNodeIndex(nodeIndex3);
		
		tri3.setNewOrientation(2);
		int[] oriIndex3 = { 3, 8, 9 };
		tri3.setOriNodeIndex(oriIndex3);
		tri3.setTriIndex(7);
		ball.add(tri3);

		//this is a special case // we set the orientation as 3
		Triangle tri4 = new Triangle();
		tri4.setLocation(ori_x + xchange * 5, ori_y + radius * 1 / 2);
		tri4.setOrientation(1);
		int[] nodeIndex4 = { 8, 12, 9 };
		tri4.setNodeIndex(nodeIndex4);
		
		tri4.setNewOrientation(1);
		int[] oriIndex4 = { 8, 12, 9 };
		tri4.setOriNodeIndex(oriIndex4);
		tri4.setTriIndex(18);
		ball.add(tri4);

		Triangle tri5 = new Triangle();
		tri5.setLocation(ori_x + xchange * 7, ori_y + radius * 1 / 2);
		tri5.setOrientation(2);
		int[] nodeIndex5 = { 12, 8, 7 };
		tri5.setNodeIndex(nodeIndex5);
		
		tri5.setNewOrientation(2);
		int[] oriIndex5 = { 12, 8, 7 };
		tri5.setOriNodeIndex(oriIndex5);
		tri5.setTriIndex(16);
		ball.add(tri5);

		Triangle tri6 = new Triangle();
		tri6.setLocation(ori_x - xchange, ori_y + radius * 3 / 2);
		tri6.setOrientation(1);
		int[] nodeIndex6 = { 2, 6, 7 };
		tri6.setNodeIndex(nodeIndex6);
		
		tri6.setNewOrientation(1);
		int[] oriIndex6 = { 2, 6, 7 };
		tri6.setOriNodeIndex(oriIndex6);
		tri6.setTriIndex(10);
		ball.add(tri6);

		Triangle tri7 = new Triangle();
		tri7.setLocation(ori_x, ori_y + radius * 2);
		tri7.setOrientation(2);
		int[] nodeIndex7 = { 1, 6, 2 };
		tri7.setNodeIndex(nodeIndex7);
		
		tri7.setNewOrientation(2);
		int[] oriIndex7 = { 1, 6, 2 };
		tri7.setOriNodeIndex(oriIndex7);
		tri7.setTriIndex(2);
		ball.add(tri7);

		Triangle tri8 = new Triangle();
		tri8.setLocation(ori_x + xchange, ori_y + radius * 3 / 2);
		tri8.setOrientation(1);
		int[] nodeIndex8 = { 2, 3, 1 };
		tri8.setNodeIndex(nodeIndex8);
		
		tri8.setNewOrientation(1);
		int[] oriIndex8 = { 2, 3, 1 };
		tri8.setOriNodeIndex(oriIndex8);
		tri8.setTriIndex(1);
		ball.add(tri8);

		Triangle tri9 = new Triangle();
		tri9.setLocation(ori_x + xchange * 2, ori_y + radius * 2);
		tri9.setOrientation(2);
		int[] nodeIndex9 = { 4, 1, 3 };
		tri9.setNodeIndex(nodeIndex9);
		
		tri9.setNewOrientation(2);
		int[] oriIndex9 = { 4, 1, 3 };
		tri9.setOriNodeIndex(oriIndex9);
		tri9.setTriIndex(5);
		ball.add(tri9);

		Triangle tri10 = new Triangle();
		tri10.setLocation(ori_x + xchange * 3, ori_y + radius * 3 / 2);
		tri10.setOrientation(1);
		int[] nodeIndex10 = { 3, 9, 4 };
		tri10.setNodeIndex(nodeIndex10);
		
		tri10.setNewOrientation(1);
		int[] oriIndex10 = { 3, 9, 4 };
		tri10.setOriNodeIndex(oriIndex10);
		tri10.setTriIndex(6);
		ball.add(tri10);

		Triangle tri11 = new Triangle();
		tri11.setLocation(ori_x + xchange * 4, ori_y + radius * 2);
		tri11.setOrientation(2);
		int[] nodeIndex11 = { 10, 4, 9 };
		tri11.setNodeIndex(nodeIndex11);
		
		tri11.setNewOrientation(2);
		int[] oriIndex11 = { 10, 4, 9 };
		tri11.setOriNodeIndex(oriIndex11);
		tri11.setTriIndex(12);
		ball.add(tri11);

		Triangle tri12 = new Triangle();
		tri12.setLocation(ori_x + xchange * 5, ori_y + radius * 3 / 2);
		tri12.setOrientation(1);
		int[] nodeIndex12 = { 9, 12, 10 };
		tri12.setNodeIndex(nodeIndex12);
		
		tri12.setNewOrientation(1);
		int[] oriIndex12 = { 9, 12, 10 };
		tri12.setOriNodeIndex(oriIndex12);
		tri12.setTriIndex(19);
		ball.add(tri12);

		Triangle tri13 = new Triangle();
		tri13.setLocation(ori_x + xchange * 6, ori_y + radius * 2);
		tri13.setOrientation(1);
		int[] nodeIndex13 = { 11, 10, 12 };
		tri13.setNodeIndex(nodeIndex13);
		
		tri13.setNewOrientation(1);
		int[] oriIndex13 = { 11, 10, 12 };
		tri13.setOriNodeIndex(oriIndex13);
		tri13.setTriIndex(20);
		ball.add(tri13);

		Triangle tri14 = new Triangle();
		tri14.setLocation(ori_x + xchange * 7, ori_y + radius * 3 / 2);
		tri14.setOrientation(1);
		int[] nodeIndex14 = { 7, 11, 12 };
		tri14.setNodeIndex(nodeIndex14);
		
		tri14.setNewOrientation(1);
		int[] OriIndex14 = { 7, 11, 12 };
		tri14.setOriNodeIndex(OriIndex14);
		tri14.setTriIndex(17);
		ball.add(tri14);

		Triangle tri15 = new Triangle();
		tri15.setLocation(ori_x - xchange, ori_y + radius * 7 / 2);
		tri15.setOrientation(1);
		int[] nodeIndex15 = { 6, 5, 11 };
		tri15.setNodeIndex(nodeIndex15);
		
		tri15.setNewOrientation(1);
		int[] oriIndex15 = { 6, 5, 11 };
		tri15.setOriNodeIndex(oriIndex15);
		tri15.setTriIndex(13);
		ball.add(tri15);

		Triangle tri16 = new Triangle();
		tri16.setLocation(ori_x, ori_y + radius * 3);
		tri16.setOrientation(2);
		int[] nodeIndex16 = { 5, 6, 1 };
		tri16.setNodeIndex(nodeIndex16);
		
		tri16.setNewOrientation(2);
		int[] oriIndex16 = { 5, 6, 1 };
		tri16.setOriNodeIndex(oriIndex16);
		tri16.setTriIndex(3);
		ball.add(tri16);

		Triangle tri17 = new Triangle();
		tri17.setLocation(ori_x + xchange * 2, ori_y + radius * 3);
		tri17.setOrientation(1);
		int[] nodeIndex17 = { 1, 4, 5 };
		tri17.setNodeIndex(nodeIndex17);
		
		tri17.setNewOrientation(1);
		int[] oriIndex17 = { 1, 4, 5 };
		tri17.setOriNodeIndex(oriIndex17);
		tri17.setTriIndex(4);
		ball.add(tri17);

		Triangle tri18 = new Triangle();
		tri18.setLocation(ori_x + xchange * 4, ori_y + radius * 3);
		tri18.setOrientation(2);
		int[] nodeIndex18 = { 10, 5, 4 };
		tri18.setNodeIndex(nodeIndex18);
		
		tri18.setNewOrientation(2);
		int[] oriIndex18 = { 10, 5, 4 };
		tri18.setOriNodeIndex(oriIndex18);
		tri18.setTriIndex(11);
		ball.add(tri18);

		Triangle tri19 = new Triangle();
		tri19.setLocation(ori_x + xchange * 5, ori_y + radius * 7 / 2);
		tri19.setOrientation(2);
		int[] nodeIndex19 = { 10, 11, 5 };
		tri19.setNodeIndex(nodeIndex19);

		tri19.setNewOrientation(2);
		int[] oriIndex19 = { 10, 11, 5 };
		tri19.setOriNodeIndex(oriIndex19);
		tri19.setTriIndex(14);
		ball.add(tri19);

		Triangle tri20 = new Triangle();
		tri20.setLocation(ori_x - xchange * 2, ori_y + radius * 3);
		tri20.setOrientation(2);
		int[] nodeIndex20 = { 11, 7, 6 };
		tri20.setNodeIndex(nodeIndex20);
		
		tri20.setNewOrientation(2);
		int[] oriIndex20 = { 11, 7, 6 };
		tri20.setOriNodeIndex(oriIndex20);
		tri20.setTriIndex(15);
		ball.add(tri20);

		
		
		for(int i = 0 ; i < 20; i ++)
		{
			ball.get(i).setRadius(this.radius);
		}
	}

	//
	public int[] findAdjacentTri(int triIndex) {
		int[] adjacent = new int[3];

		surface s = index.faces.get(triIndex);

		int count = -1;

		for (int i = 1; i < index.faces.size() + 1; i++) {
			if (i != triIndex) {
				surface comp = index.faces.get(i);
				if (((comp.getEdge_id1() == s.getEdge_id1())
						|| (comp.getEdge_id1() == s.getEdge_id2()) || (comp
							.getEdge_id1() == s.getEdge_id3()))) {
					count += 1;
					adjacent[count] = i;
				} else if (((comp.getEdge_id2() == s.getEdge_id1())
						|| (comp.getEdge_id2() == s.getEdge_id2()) || (comp
							.getEdge_id2() == s.getEdge_id3()))) {
					count += 1;
					adjacent[count] = i;
				} else if (((comp.getEdge_id3() == s.getEdge_id1())
						|| (comp.getEdge_id3() == s.getEdge_id2()) || (comp
							.getEdge_id3() == s.getEdge_id3()))) {
					count += 1;
					adjacent[count] = i;
				}

			}
		}

		return adjacent;
	}

	public int[] findJointNode(int triIndex) {
		int[] adjacent = new int[5];

		return adjacent;
	}

	// the first one is the moved one, the second is the fixed one
	public void reshapeIco(int moveTri, int fixTri) {
		// TODO Auto-generated method stub
		Point2D centerMove = this.ball.get(moveTri).getLocation();
		Point2D centerFix = this.ball.get(fixTri).getLocation();

		if (!isPhysicalAdjacent(centerMove, centerFix)) {
			// if not physicalAdjacent, make them together
			this.ball.get(moveTri).MoveToAd(this.ball.get(fixTri));
		}

	}

	private Triangle getByIndex(int fixTri, ArrayList<Triangle> ball) {
		// TODO Auto-generated method stub
		for(int i = 0; i < ball.size(); i ++)
		{
			if(ball.get(i).getTriIndex() == fixTri){
				return ball.get(i);
			}
		}
		return null;
	}

	public boolean isPhysicalAdjacent(Point2D centerMove, Point2D centerFix) {
		// TODO Auto-generated method stub
		double dis = centerMove.distance(centerFix);
		if (Math.abs(dis - this.radius)<4) {
			return true;
		} else {
			return false;
		}

	}

	public int[] findRotate(int triIndex) {
		// TODO Auto-generated method stub
	    
		
		return null;
	}

	public int[] finMoveToTriangle(int triIndex) {
		// TODO Auto-generated method stub
		return null;
	}

	public ArrayList<Triangle> getPossibleChange(int center, int[] adjTriangle) {
		// TODO Auto-generated method stub
		
		ArrayList<Triangle> ps = new ArrayList<Triangle>();
		for(int i = 0; i < 3; i ++){
			// the first one is the moved one, the second is the fixed one
			Triangle e = getPossibleTriangle(center, adjTriangle[i]);
			if(e!=null){
				ps.add(e);
			}
		}
		
		return ps;
	}
	
	

	private Triangle getPossibleTriangle(int center, int i) {
		// TODO Auto-generated method stub
		// TODO Auto-generated method stub
		
		Triangle tempt = new Triangle();
		tempt.copy(this.ball.get(center));
		
		Point2D centerMove = tempt.getLocation();
		Point2D centerFix = getByIndex(i, ball).getLocation();

		if (!isPhysicalAdjacent(centerMove, centerFix)) {
			// if not physicalAdjacent, make them together
			tempt.MoveToAd(getByIndex(i, ball));
		}else{
			return null;
		}

		
		return tempt;
	}

	public ArrayList<Operations> getPossibleChanges(int center, int[] adjTriangle) {
		// TODO Auto-generated method stub
		
		ArrayList<Operations> ps = new ArrayList<Operations>();
		for(int i = 0; i < 3; i ++){
			// the first one is the moved one, the second is the fixed one
			Operations o = getPossibleOperation(center, adjTriangle[i]);
			
			if(o!=null){
				ps.add(o);
			}
		}
		
		return ps;
	}
	
	private Operations getPossibleOperation(int center, int i) {
		// TODO Auto-generated method stub
		// TODO Auto-generated method stub
		
		Operations op = new Operations();
		
		Triangle tempt = new Triangle();
		tempt.copy(this.ball.get(center));
		
		op.tb.copy(tempt);
		
		Point2D centerMove = tempt.getLocation();
		Point2D centerFix = getByIndex(i, ball).getLocation();
		
		Point2D p = null;
		
        double angle = 0;
        Point2D movedis = null;
        
		if (!isPhysicalAdjacent(centerMove, centerFix)) {
			// if not physicalAdjacent, make them together
			
		//	int nodeindex = tempt.findPysicalJointNode(getByIndex(i,ball));
			p = tempt.getPhysicalJointNode(getByIndex(i,ball));
			if(p != null){
			angle = - tempt.getRotate(getByIndex(i,ball));
			}
			tempt.MoveToAd(getByIndex(i, ball));
			if(p == null)
			{
			 	Point2D tempd = new Point2D.Float((float)(tempt.getX() - centerMove.getX()), (float)(tempt.getY() - centerMove.getY()));
			 	movedis = tempd;
			}else{
		
			
			}
		}else{
			return null;
		}
		
		op.te.copy(tempt);
		op.jointNode = p;
		op.angle = angle;

		return op;
	}

}
